using System.Linq;
using Arcane.Source.Client;
using Arcane.Source.Combat.Items;
using Arcane.Source.UI;
using Godot;

namespace Arcane.Source.Combat
{
    public partial class CombatView : Node, IView
    {
        [Export]
        public Control UI { get; set; }

        public Node Node => this;

        public GameOS Os { get; set; }

        #region UI Bindings
        [Export]
        PackedScene _statusAuraPrefab;
        [Export]
        RuneMatcher _matcher;
        [Export]
        Range _playerHealth, _enemyHealth;
        [Export]
        Range _playerEnergy, _enemyEnergy;
        [Export]
        Node _playerAuraMount, _enemyAuraMount;
        [Export]
        Range _playerUltra, _enemyUltra;
        [Export]
        Control _endOverlay;
        #endregion

        #region Events
        public event System.Action CastUltraTriggered;
        public event System.Action ToggleAutoUltra;
        public event System.Action PauseTriggered;
        public event System.Action CloseTriggered;
        #endregion

        public override void _Input(InputEvent e)
        {
            if (e is InputEventKey ke)
            {
                if (ke.Pressed && ke.Keycode == Key.Escape)
                {
                    RequestPause();
                }
            }
        }

        private void OnFree()
        {
            PauseTriggered -= PauseTriggered;
        }

        public void ShowWinning(int index)
        {
            if (_endOverlay == null) return;
            _endOverlay.GetNode<Label>("Label").Text = index == 0 ? "You Win!" : "You lose!";
            _endOverlay.Visible = true;
        }

        public void BindCombat(CombatContext context)
        {
            context.player.PrintTriggerNames();
            var matchCtrl = context.player.RuneCtrl;
            _matcher.Setup(matchCtrl.Match, matchCtrl.RuneNames.ToArray());

            BindHealthBar(context.player, _playerHealth);
            BindEnergyBar(context.player, _playerEnergy);
            BindAuras(context.player, _playerAuraMount);

            BindHealthBar(context.enemy, _enemyHealth);
            BindEnergyBar(context.enemy, _enemyEnergy);
            BindAuras(context.enemy, _enemyAuraMount);
        }

        public void SetAutoUltra(bool isOn)
        {
            _playerUltra.Call("turn_switch_no_signal", isOn);
        }

        private void RequestCastUltra()
        {
            CastUltraTriggered?.Invoke();
        }

        private void RequestToggleAutoUltra()
        {
            ToggleAutoUltra?.Invoke();
        }

        private void RequestPause()
        {
            PauseTriggered?.Invoke();
        }

        private void RequestClose()
        {
            CloseTriggered?.Invoke();
        }

        private static void BindEnergyBar(Entity entity, Range bar)
        {
            bar.MaxValue = entity.MaxEnergy;
            bar.MinValue = 0;
            bar.Value = entity.Energy;

            entity.OnEnergyChange += (val) => bar.Value = val;
        }

        private static void BindHealthBar(Entity entity, Range bar)
        {
            bar.MaxValue = entity.maxHealth;
            bar.MinValue = 0;
            bar.Value = entity.Health;

            entity.OnHealthChange += (val) => bar.Value = val;
        }

        private void BindAuras(Entity entity, Node mnt)
        {
            entity.OnAddStatusEffect += (name, eff) =>
            {
                var aura = _statusAuraPrefab.Instantiate<Aura>();

                mnt.AddChild(aura.Bind(name, eff));
            };
        }
    }
}